package org.fglxy.mockserver.service;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.fglxy.mockserver.dto.CreateMockTaskRequest;
import org.fglxy.mockserver.dto.DeleteMockRequest;
import org.fglxy.mockserver.dto.DeleteTaskRequest;
import org.fglxy.mockserver.entity.MockEndEntity;
import org.fglxy.mockserver.entity.MockTaskEntity;
import org.fglxy.mockserver.enums.RetCodeEnum;
import org.fglxy.mockserver.exception.MessageException;
import org.fglxy.mockserver.mock.IMockEnd;
import org.fglxy.mockserver.mock.MockClient;
import org.fglxy.mockserver.mock.MockServer;
import org.fglxy.mockserver.util.IdFactoryUtils;
import org.fglxy.mockserver.util.ResourceUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
public class MockService {

	private ConcurrentHashMap<String, IMockEnd> mockMaps = new ConcurrentHashMap<String, IMockEnd>();
	
	@PostConstruct
	public void init() {
		ResourceUtils.initResourcePath();
	}

	public void createMock(MockEndEntity entity, MultipartFile descript, MultipartFile cmdNos) {
		entity.setId(IdFactoryUtils.generateId());
		this.modifyMock(entity, descript, cmdNos);
	}

	public void modifyMock(MockEndEntity entity, MultipartFile descript, MultipartFile cmdNos) {
		ResourceUtils.writeLock(entity.getId());
		try {
			ResourceUtils.writeMockBaseConfig(entity);
			if (descript != null) {
				ResourceUtils.writeMockDescript(entity.getId(), descript);
			}
			if (cmdNos != null) {
				ResourceUtils.writeMockCmdNos(entity.getId(), cmdNos);
			}
		} finally {
			ResourceUtils.releaseWriteLock(entity.getId());
		}
	}
	
	/**
	 * 删除mock任务不影响正在跑的mock。除非重新加载
	 * @param request
	 */
	public void deleteMock(DeleteMockRequest request) {
		ResourceUtils.writeLock(request.getMockId());
		try {
			ResourceUtils.deleteMock(request.getMockId());
		} finally {
			ResourceUtils.releaseWriteLock(request.getMockId());
		}
	}

	public void createTask(CreateMockTaskRequest request) {
		ResourceUtils.writeLock(request.getMockId());
		try {
			MockTaskEntity entity = new MockTaskEntity();
			BeanUtils.copyProperties(request, entity);
			ResourceUtils.writeMockTask(request.getMockId(), entity);
		} finally {
			ResourceUtils.releaseWriteLock(request.getMockId());
		}
	}

	public void deleteTask(DeleteTaskRequest request) {
		ResourceUtils.writeLock(request.getMockId());
		try {
			ResourceUtils.deleteMockTask(request.getMockId(), request.getTaskName());
		} finally {
			ResourceUtils.releaseWriteLock(request.getMockId());
		}
	}

	public void runMock(String id) {
		// mock计划已经创建过了，就直接重启即可
		if (this.mockMaps.containsKey(id)) {
			this.mockMaps.get(id).restart();
			return;
		}
		MockEndEntity entity;
		try {
			entity = ResourceUtils.getMockBaseConfig(id);
		} catch (IOException e) {
			throw new MessageException(RetCodeEnum.NO_MOCK, e);
		}
		if (entity == null) {
			throw new MessageException(RetCodeEnum.NO_MOCK);
		}
		if (entity.isServerFlag()) {
			startMockServer(entity);
		} else {
			startMockClient(entity);
		}
	}

	private void startMockClient(MockEndEntity entity) {
		MockClient newClient = new MockClient(entity);
		MockClient client = (MockClient) this.mockMaps.putIfAbsent(entity.getId(), newClient);
		client = client == null ?  newClient : client;
		client.init();
		client.start();
	}

	private void startMockServer(MockEndEntity entity) {
		MockServer newServer = new MockServer(entity);
		MockServer server = (MockServer) this.mockMaps.putIfAbsent(entity.getId(), newServer);
		server = server == null ?  newServer : server;
		server.init();
		server.start();
	}

}
